#!/bin/sh
# LambdaNative - a cross-platform Scheme framework
# Copyright (c) 2009-2013, University of British Columbia
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the
# following conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# * Neither the name of the University of British Columbia nor
# the names of its contributors may be used to endorse or
# promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

android_subst()
{
  d=$1
  ac_subst ANDROID_C_DEFINES "@$d/ANDROID_c_defines"
  ac_subst ANDROID_C_ADDITIONS "@$d/ANDROID_c_additions"
  ac_subst ANDROID_JAVA_IMPORTS "@$d/ANDROID_java_imports"
  ac_subst ANDROID_JAVA_IMPLEMENTS "@$d/ANDROID_java_implements"
  ac_subst ANDROID_JAVA_VARIABLES "@$d/ANDROID_java_variables"
  ac_subst ANDROID_JAVA_ONCREATE "@$d/ANDROID_java_oncreate"
  ac_subst ANDROID_JAVA_ONPAUSE "@$d/ANDROID_java_onpause"
  ac_subst ANDROID_JAVA_ONRESUME "@$d/ANDROID_java_onresume"
  ac_subst ANDROID_JAVA_ONDESTROY "@$d/ANDROID_java_ondestroy"
  ac_subst ANDROID_JAVA_ONSENSORCHANGED "@$d/ANDROID_java_onsensorchanged"
  ac_subst ANDROID_JAVA_ONACTIVITYRESULT "@$d/ANDROID_java_onactivityresult"
  ac_subst ANDROID_JAVA_ACTIVITYADDITIONS "@$d/ANDROID_java_activityadditions"
  ac_subst ANDROID_JAVA_ADDITIONS "@$d/ANDROID_java_additions"
  ac_subst ANDROID_XML_PERMISSIONS "@$d/ANDROID_xml_permissions"
  ac_subst ANDROID_INTENT_FILTERS "@$d/ANDROID_intent_filters"
  ac_subst ANDROID_XML_RECEIVERS "@$d/ANDROID_xml_receivers"
  ac_subst ANDROID_XML_SERVICES "@$d/ANDROID_xml_services"
  ac_subst ANDROID_ACTIVITY_ATTRIBUTES "@$d/ANDROID_activity_attributes"
  # This is a terrible hack to solve the problem with android:usesCleartextTraffic
  # not being available for APIs <23, but being required above it.
  if [ $SYS_ANDROIDAPI -lt 23 ]; then
    ac_subst ANDROID_APPLICATION_ATTRIBUTES ""
    vecho "WARNING: Removed ANDROID_APPLICATION_ATTRIBUTES substitutions for API levels <23"
  else
    ac_subst ANDROID_APPLICATION_ATTRIBUTES "@$d/ANDROID_application_attributes"
  fi
}
android_subst loaders/android

NEED_GCM=no
for m in $modules; do
  modpath=`locatedir modules/$m silent`
  android_subst $modpath
  if [ -e $modpath/ANDROID_xml_permissions ]; then
    if grep com.google.android.c2dm $modpath/ANDROID_xml_permissions; then
      NEED_GCM=yes;
    fi
  fi
done
android_subst `locatedir apps/$SYS_APPNAME`

if [ "X$ANDROIDSDK" = "X" ]; then
  echo "ERROR: \$ANDROIDSDK is empty - ensure your SETUP file returns a valid sdk path."
  exit
fi

use_android_tool=yes

if [ -x "$ANDROIDSDK/tools/bin/avdmanager" ]; then
  echo " == this SDK is gradle based, adjusting for ant build.."
  touch $ANDROIDSDK/testwr
  assertfile $ANDROIDSDK/testwr "Unsupported sdk tools, and sdk not writable. Giving up."
  rm $ANDROIDSDK/testwr
  if [ ! -d $ANDROIDSDK/tools.gradle ]; then
    mv $ANDROIDSDK/tools $ANDROIDSDK/tools.gradle
  fi
  if [ -e $ANDROIDSDK/tools ]; then
    rm $ANDROIDSDK/tools
  fi
  # get the latest supported ant build version
  if [ ! -d $ANDROIDSDK/tools.ant ]; then
    echo " == downloading tools for ant build.."
    dir_antbuild=`pwd`
    cd $ANDROIDSDK
    if [ -f ant_tools.zip ]; then
      rm ant_tools.zip
    fi
    wget http://dl.google.com/android/repository/tools_r25.2.5-$SYS_HOSTPLATFORM.zip -O ant_tools.zip
    asserterror $? "download failed"
    unzip -q ./ant_tools.zip
    rm ant_tools.zip
    mv tools tools.ant
    cd tools.ant/lib
    ln -s x86_64 aarch64
    cd "$dir_antbuild"
  fi
  # point us to the ant tools
  ln -s $ANDROIDSDK/tools.ant $ANDROIDSDK/tools
fi

echo " => creating android project.."
#tmpdir=`mktemp -d $SYS_TMPDIR/tmp.XXXXXX`
tmpdir="$SYS_TMPDIR/tmp_build"
if [ -d "$tmpdir" ]; then
  rm -rf "$tmpdir"
fi
mkdir -p "$tmpdir"

if [ $use_android_tool = no ]; then
  ANDROIDSDKTARGET=`$ANDROIDSDK/tools/bin/avdmanager list target | grep "^id:" | grep "android-$SYS_ANDROIDAPI" | cut -f 2 -d " "`
else
  ANDROIDSDKTARGET=`$ANDROIDSDK/tools/android list targets | grep "^id:" | grep "android-$SYS_ANDROIDAPI" | cut -f 2 -d " "`
fi
if [ "X$ANDROIDSDKTARGET" = "X" ]; then
  echo "ERROR: API $SYS_ANDROIDAPI not a target."
  exit
else
  echo " => using target $ANDROIDSDKTARGET [API $SYS_ANDROIDAPI]"
fi

if [ $use_android_tool = yes ]; then
$ANDROIDSDK/tools/android --silent create project \
  --target $ANDROIDSDKTARGET --name $SYS_APPNAME --path $tmpdir \
  --activity $SYS_APPNAME --package $SYS_PACKAGE_DOT
else
assert "### Gradle is not supported"
fi

# try to include support.v4 library
if [ -f $ANDROIDSDK/extras/android/support/v4/android-support-v4.jar ]; then
  cp -r $ANDROIDSDK/extras/android/support/v4/android-support-v4.jar $tmpdir/libs
  echo " => support-v4 library loaded"
else
  # look for support-v4 in alternate location
  # special support for API 19
  if [ $SYS_ANDROIDAPI -eq "19" ]; then
    if [ -f $ANDROIDSDK/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0.jar ]; then
      cp -r $ANDROIDSDK/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0.jar $tmpdir/libs
      echo " => support-v4 library loaded (version 19)"
    fi
  else
  # Find the directory containing the support-v4 AAR file
  # Only folders from 20 - 23 have the full AAR file needed
    supportv4version=$SYS_ANDROIDAPI
    if [ $supportv4version -gt 23 ]; then
      supportv4version="23"
    fi
    v4dir=""
    while [ $supportv4version -gt "19" ]; do
      v4dir=`find $ANDROIDSDK/extras/android/m2repository/com/android/support/support-v4 -name "$supportv4version*" | grep -v -e "alpha" -e "beta" | sort | tail -1`
      if [ ! "X$v4dir" = "X" ]; then
        break
      fi
      supportv4version=`expr ${supportv4version} - 1`
    done
    # If a directory is found, check if classes.jar has already been extracted. If not, extract it from the AAR
    if [ ! "X$v4dir" = "X" ]; then
      v4file=`find $v4dir -name classes.jar`
      if [ ! -s "$v4file" ]; then
        if [ -d $SYS_PREFIXROOT/android/support ]; then
          v4file=`find $SYS_PREFIXROOT/android/support -name $supportv4version-classes.jar`
        fi
      fi
      if [ ! -s "$v4file" ]; then
        v4aar=`find $v4dir -name support-v4*.aar`
        if [ -s "$v4aar" ]; then
          unzip $v4aar classes.jar -d $SYS_PREFIXROOT/android/support > /dev/null && mv $SYS_PREFIXROOT/android/support/classes.jar $SYS_PREFIXROOT/android/support/$supportv4version-classes.jar
          v4file=`find $SYS_PREFIXROOT/android/support -name $supportv4version-classes.jar`
        fi
      fi
      # If a classes.jar file has been found, copy it to libs
      if [ -s "$v4file" ]; then
        cp -r $v4file $tmpdir/libs/classes.jar
        echo " => support-v4 library loaded (version $supportv4version)"
      else
        echo " => warning: support-v4 library not found"
      fi
    else
      echo " => warning: support-v4 library not found"
    fi
  fi
fi

if [ "$NEED_GCM" = "yes" ]; then
  cp -r $ANDROIDSDK/extras/google/google_play_services/libproject/google-play-services_lib $tmpdir
  cp -r $ANDROIDSDK/extras/android/support/v4/android-support-v4.jar $tmpdir/libs
  cp $tmpdir/build.xml $tmpdir/google-play-services_lib
  cp $tmpdir/local.properties $tmpdir/google-play-services_lib

  if [ $use_android_tool = yes ]; then
    $ANDROIDSDK/tools/android --silent update project \
      --target $ANDROIDSDKTARGET --path $tmpdir \
      --library ./google-play-services_lib
  else
    assert "### gradle is not supported"
  fi

fi

echo " => preparing icons.."
mkdir -p $tmpdir/res/drawable
cp $SYS_PREFIXROOT/build/$SYS_APPNAME/artwork-72.png $tmpdir/res/drawable/icon.png

# transfering sound files
make_soundfile_android()
{
  mkdir -p $tmpdir/res/raw
  locasesnd=`basename "$1" | tr A-Z a-z`
  cp "$1" $tmpdir/res/raw/$locasesnd
}
  make_sounds make_soundfile_android

# transfering jar files
jarfilesdir=`locatedir apps/$SYS_APPNAME/android_jars silent`
if [ -d "$jarfilesdir" ]; then
  echo " => transfering jar files.."
  jarfiles=`ls -1 $jarfilesdir/*.jar 2> /dev/null`
  mkdir -p $tmpdir/libs/
  for jar in $jarfiles; do
    locajar=`basename $jar | tr A-Z a-z`
    vecho " => copying jar file - $locajar ..."
    cp $jar $tmpdir/libs/
  done
fi

# tranfer xml
xmlfilesdir=`locatedir apps/$SYS_APPNAME/xml silent`
if [ -d "$xmlfilesdir" ]; then
  echo " => transferring xml files ..."
  mkdir -p $tmpdir/res/xml/
  xmlfiles=`ls -1 $xmlfilesdir/*.xml 2> /dev/null`
  for xml in $xmlfiles; do
    vecho " => copying xml file - $xml ..."
    cp $xml $tmpdir/res/xml/
  done
fi

echo " => transferring java hook.."
appdir=$tmpdir/src/$SYS_PACKAGE_SLASH
ac_output loaders/android/bootstrap.java.in $appdir/$SYS_APPNAME.java

echo " => transferring java public classes and jars from modules.."
for m in $modules; do
  modpath=`locatedir modules/$m silent`
  pubclasses=`ls -1 $modpath/ANDROID_java_public_* 2> /dev/null`
  for pubclass in $pubclasses; do
    pubclassfile="`basename $pubclass | sed 's/ANDROID_java_public_//'`.java"
    echo "    $pubclassfile.."
    if [ "`echo $pubclass | cut -d . -f 2`" = "in" ]; then
      pubclassfile=`echo $pubclassfile | sed 's/.in//'`
      ac_output $pubclass $appdir/$pubclassfile
    else
      echo "package $SYS_PACKAGE_DOT;" > $appdir/$pubclassfile
      cat $pubclass >> $appdir/$pubclassfile
    fi
  done
  if [ -d $modpath/android_jars ]; then
    echo " => transferring jars.."
    test -d $tmpdir/libs || mkdir -p $tmpdir/libs
    cp $modpath/android_jars/*.jar $tmpdir/libs
  fi
done

echo " => preparing manifest.."
ac_output loaders/android/AndroidManifest.xml.in $SYS_TMPDIR/tmp.xml
cat $SYS_TMPDIR/tmp.xml | sed '/^#/d' > "$tmpdir/AndroidManifest.xml"
rmifexists $SYS_TMPDIR/tmp.xml

echo " => creating payload module.."
tmpmoddir=`mktemp -d $SYS_TMPDIR/tmp.XXXXXX`
mkdir $tmpmoddir/libpayload
cp loaders/android/Android.mk.module $tmpmoddir/libpayload/Android.mk

# Loop over possible architectures and copy their precompiled files
SYS_ANDROID_ABIs=`echo $SYS_ANDROID_ABIs | awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s%s",$i,FS)}{printf("\n")}'`
for abi in $SYS_ANDROID_ABIs; do
  case "$abi" in
  armeabi-v7a)
    arch=arm
  ;;
  arm64-v8a)
    arch=arm64
  ;;
  x86)
    arch=x86
  ;;
  x86_64)
    arch=x86_64
  ;;
  esac
  if [ "X$SYS_MODE" = "Xdebug" ]; then
    lib=$SYS_PREFIXROOT/android-debug/${arch}${SYS_PLATFORM_VARIANT}/lib/libpayload.a
  else
    lib=$SYS_PREFIXROOT/android/${arch}${SYS_PLATFORM_VARIANT}/lib/libpayload.a
  fi
  if [ -f $lib ]; then
    mkdir $tmpmoddir/libpayload/$abi
    cp $lib $tmpmoddir/libpayload/$abi
  fi
done

echo " => preparing JNI.."
mkdir $tmpdir/jni
ac_output loaders/android/Android.mk.jni.in $tmpdir/jni/Android.mk
cp $SYS_PREFIX/include/LNCONFIG.h $tmpdir/jni
ac_output loaders/android/bootstrap.c.in $tmpdir/jni/bootstrap.c
cd $tmpdir

if [ $SYS_MODE = "debug" ]; then
  echo " => compiling payload module with debug options.."
  veval "NDK_MODULE_PATH=$tmpmoddir $ANDROIDNDK/ndk-build APP_ABI=\"$SYS_ANDROID_ABIs\" NDK_LOG=1 NDK_DEBUG=1"
else
  echo " => compiling payload module.."
  veval "NDK_MODULE_PATH=$tmpmoddir $ANDROIDNDK/ndk-build --silent APP_ABI=\"$SYS_ANDROID_ABIs\""
fi
asserterror $?

echo " => adding precompiled libaries.."
for lib in $payload_libs; do
  if [ -f "$SYS_PREFIX/lib/$lib.jar" ]; then
    cp $SYS_PREFIX/lib/$lib.jar $tmpdir/libs/
  fi
done

# manage hybrid apps
if [ `has_module hybridapp` = yes ]; then
  echo " => adding webview.."
cat > $tmpdir/res/layout/main.xml << __EOF
<WebView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/webview_main"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
/>
__EOF
fi

if [ `has_module hybridapp-xwalk` = yes ]; then
  echo " => adding crosswalk.."
  if [ -d $SYS_PREFIX/lib/libxwalk ]; then
    rmifexists "$SYS_TMPDIR/libxwalk"
    cp -R -f $SYS_PREFIX/lib/libxwalk $SYS_TMPDIR/
    if [ ! -d $SYS_TMPDIR/libxwalk/libs/armeabi ] && [ $SYS_ANDROID_ABI = armeabi ]; then
      mv $SYS_TMPDIR/libxwalk/libs/armeabi-v7a $SYS_TMPDIR/libxwalk/libs/armeabi
    fi
    xwalk_here=`pwd`
    cd $tmpdir
    if [ $use_android_tool = yes ]; then
      $ANDROIDSDK/tools/android --silent update project --target $ANDROIDSDKTARGET --path $tmpdir --library ../libxwalk
    else 
      assert "## gradle is not supported"
    fi
    cd "$xwalk_here"
cat > $tmpdir/res/layout/main.xml << __EOF
<org.xwalk.core.XWalkView android:id="@+id/xwalk_main"
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
</org.xwalk.core.XWalkView>
__EOF
  else
    assert "crosswalk library not found?" 
  fi
fi

# allow free rotation of hybrid apps
if [ `has_module hybridapp hybridapp-xwalk` = yes ]; then
  cp $tmpdir/src/$SYS_PACKAGE_SLASH/$SYS_APPNAME.java tmp.java
  cat tmp.java | sed '/SCREEN_ORIENTATION_PORTRAIT/d' > $tmpdir/src/$SYS_PACKAGE_SLASH/$SYS_APPNAME.java
  rm tmp.java
fi

echo " => compiling application.."
if [ -n "$JAVAVERSION" ]; then
  echo "java.target = $JAVAVERSION" >> $tmpdir/ant.properties
  echo "java.source = $JAVAVERSION" >> $tmpdir/ant.properties
fi
veval "ant release"
asserterror $?
cd $here
pkgfile="$tmpdir/bin/$(echo $SYS_APPNAME)-release-unsigned.apk"
assertfile "$pkgfile"

echo " => transferring application.."
fnlfile="$SYS_PREFIXROOT/packages/$SYS_APPNAME-$SYS_APPVERSION-$SYS_PLATFORM${SYS_PLATFORM_VARIANT}.apk"
cp $pkgfile $fnlfile
assertfile $fnlfile

# Signing the binary
keystore=`locatefile PROFILE | sed 's/PROFILE$/android\.keystore/'`
if [ ! -f "$keystore" ]; then
  keystore=$SYS_TMPDIR/android.keystore
fi
keytool -list -keystore $keystore -alias $SYS_ORGDOMAIN_REVERSE_DOT -storepass "$SYS_ANDROIDPW" > /dev/null || (
  echo " => generating keystore [$keystore].."
  keytool -genkey -v -keystore $keystore -dname "CN=$SYS_ORGDOMAIN_REVERSE_DOT" -alias "$SYS_ORGDOMAIN_REVERSE_DOT" -keyalg RSA -keysize 2048 -validity 10000 -storetype PKCS12 -storepass "$SYS_ANDROIDPW" -keypass "$SYS_ANDROIDPW"
  asserterror $?
)

echo " => zipaligning.."
assertfile $fnlfile
mv $fnlfile $SYS_TMPDIR/tmp.apk
if [ -x $ANDROIDSDK/tools/zipalign ]; then
  $ANDROIDSDK/tools/zipalign -f 4 $SYS_TMPDIR/tmp.apk $fnlfile
else
  `ls -1 $ANDROIDSDK/build-tools/*/zipalign | tail -n 1` -f 4 $SYS_TMPDIR/tmp.apk $fnlfile
fi
asserterror $?
rmifexists $SYS_TMPDIR/tmp.apk

echo " => signing application with keystore $keystore"
$ANDROIDSDK/build-tools/*/apksigner sign -v --ks $keystore --ks-key-alias "$SYS_ORGDOMAIN_REVERSE_DOT" --ks-pass pass:"$SYS_ANDROIDPW" --v2-signing-enabled true $fnlfile
asserterror $?

echo " => cleaning up.."
rm -rf $tmpmoddir
if [ $SYS_MODE = "debug" ]; then
  echo "DEBUG: android build is in $tmpdir"
else
  rm -rf $tmpdir
fi

if [ -d  $ANDROIDSDK/tools.gradle ]; then
  echo " == restoring gradle build."
  rm $ANDROIDSDK/tools
  ln -s $ANDROIDSDK/tools.gradle $ANDROIDSDK/tools
fi

#eof
